;;; Copyright (c) 1999 Massachusetts Institute of Technology
;;;
;;; This program is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU General Public License as
;;; published by the Free Software Foundation; either version 3 of the
;;; License, or (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program; if not, see https://gnu.org/licenses or
;;; write to:
;;;  Free Software Foundatiom, Inc.
;;;  51 Franklin St, Fifth Floor
;;;  Boston, MA 02110-1301
;;;  USA

;I T S .OPERS RELEVANT TO REAL TIME

		;.PDTIME AC,	;RETURNS PDUPS*<# SECS SINCE BEGINNING OF YEAR>

APDTIM:	PUSHJ P,GPDTIM
	 JRST RETM1		;-1 IF NOT KNOWN
	JRST APTUAJ

		;.RDATE AC,	;RETURNS SIXBIT YYMMDD IN AC

ARDATE:	PUSHJ P,GLPDTM	;GET LOCALIZED PDTIME
	 JRST RETM1	;NOT AVAILABLE
	IDIVI A,SPD	;GET # DAYS SINCE BEGINNING OF YEAR
	PUSHJ P,RDATE	;GET THE ANSWER
	JRST APTUAJ	;RETURN IT

		;.RTIME AC,	;RETURNS SIXBIT HHMMSS (24 HOUR TIME) IN AC

ARTIME:	PUSHJ P,GLPDTM	;GET LOCALIZED PDTIME
	 JRST RETM1	;NOT AVAILABLE
	IDIVI A,SPD	;GET # SECS SINCE MIDNIGHT IN B
	PUSHJ P,RTIME	;CONVERT TO SIXBIT HHMMSS
	JRST APTUAJ	;RETURN IT

		;.RDATIM AC,	;DOES .RTIME TO AC, .RDATE TO AC+1

ARDATI:	PUSHJ P,GLPDTM	;GET CRUD
	 JRST RETM1	;NO LUCK (THIS IS GETTING BORING)
	IDIVI A,SPD	;CONVERT TO DAYS AND SECONDS
	HRLM A,(P)	;SAVE DAYS ON PDL
	PUSHJ P,RTIME	;GET TIME (HHMMSS)
	UMOVEM A,(J)	;GIVE TO USER
	HLRZ A,(P)	;GET DAYS AGAIN
	PUSHJ P,RDATE	;CONVERT TO SIXBIT
	AOJA J,APTUAJ	;GIVE TO USER AND RETURN

		;.RYEAR AC,	;PUSHJ'S TO RYEAR AND MOVEM'S E TO AC

ARYEAR:	PUSHJ P,RYEAR	;GET THE CRUFT
	UMOVEM E,(J)	;STORE YEAR AND CRUD
	POPJ P,

		;.RLPDT AC,	;DOES .RYEAR AC+1, AND ALSO MOVEM'S A TO AC

ARLPDT:	PUSHJ P,RYEAR	;GET THE CRUFT
	UMOVEM E,1(J)	;STORE YEAR AND CRUD
	JRST APTUAJ	;STORE TIME AND RETURN

		;ROUTINE TO RETURN -1 ON AN OPER

RETM1:	XCTR XRW,[SETOM (J)]
	POPJ P,

		;GET THE CORRECTED PDUPS*<# SECS SINCE BEGINNING OF YEAR> IN A
		;SKIP IF OFFSET AVAILABLE AND CLOCK ON

GPDTIM:
IFN PDCLKP,[
	SKIPN A,PDTIME	;GET THE OFFSET
	 JRST GPDTM2	;NOT AVAILABLE
	DATAI PDCLK,B	;GET WHAT THE CLOCK IS SAYING
	TLZ B,600000
	JUMPE B,GPDTM2	;POWER PROBABLY (BUT NOT NECESSARILY) TURNED OFF
	SUBM B,A	;DO THE CORRECTION
	JUMPL A,CPOPJ	;LOST, DON'T RETURN A NEGATIVE NUMBER!
	JRST POPJ1	;EXIT SKIPPING (SUCCESS)
] ;PDCLKP
IFN KS10P,[
	SKIPN PDTIME	; Offset available?
	 JRST GPDTM2	; No:  Try backup
	RDTIM A		; Read clock into A!B
	TLC A,1729.	; "A most interesting number"
	TLNE A,-1	; Does the clock look like it has been set?
	 JRST GPDTM2	; Must have been reset
	DIVI A,KSFREQ	; Convert to 60ths
	SUB A,PDTIME	; Subtract offset
	JUMPL A,CPOPJ	; Wooops, don't return a negative number!  (Why
			; don't we use the backup in this case?)
	JRST POPJ1
] ;KS10P
GPDTM2:	SKIPGE A,PDYTIM	;CLOCK NOT ON, TRY BACKUP
	 POPJ P,	;SORRY, NOT AVAILABLE
	IMULI A,30.	;CONVERT TO SIXTIETHS OF A SECOND
	JRST POPJ1	;CALL IT CORRECT AND AVAILABLE

		;GET SIXBIT YYMMDD (DATE) IN A (LOCALIZED PDTIME/SPD IN A, YEAR IN RH(E))

RDATE:	PUSHJ P,RDATE1	;GET DAY IN C, MONTH IN B
	MOVE T,[1400,,A];SET UP BYTE POINTER FOR OUTPUT
	PUSHJ P,RDATM1	;DEPOSIT DAY
	MOVE C,B	;GET MONTH
	PUSHJ P,RDATM1	;DEPOSIT MONTH
	MOVEI B,(E)	;GET YEAR
	IDIVI B,100.	;GET LAST TWO DIGITS IN C
ARTIMX:	PUSHJ P,RDATM1	;DEPOSIT YEAR (ENTRY FROM RTIME TO DEPOSIT HOUR)
	IOR A,[SIXBIT /000000/]	;CONVERT TO REAL SIXBIT
	POPJ P,

		;GET MONTH (1 => JAN) IN B, DAY (1 => THE FIRST) IN C

RDATE1:	AOS C,A		;GET DAY OF YEAR (LOCALIZED) (1 => THE FIRST)
	MOVEI B,12.	;INITIALLY ASSUME DECEMBER FOR MONTH
	CAMG C,LMNTBL-1(B)	;IF DAY IN YEAR .LE. DAY IN YEAR AT BEGINNING OF THIS MONTH,
	 SOJA B,.-1	;THEN DECREMENT TO PREVIOUS MONTH AND TRY AGAIN
	SUB C,LMNTBL-1(B)	;C(C) := DAY OF MONTH
	POPJ P,

LMNTBL:	MNIRP [<M 1>]	;TABLE OF DAYS GONE BY AT BEGINNING OF MONTH

		;GET THE SIXBIT TIME IN A (# SECS SINCE MIDNIGHT IN B)

RTIME:	MOVE T,[1400,,A];SET UP BYTE POINTER FOR OUTPUT
	IDIVI B,60.	;GET SECONDS IN C
	PUSHJ P,RDATM1	;DEPOSIT INTO A
	IDIVI B,60.	;GET HOURS IN B, MINUTES IN C
	PUSHJ P,RDATM1	;DEPOSIT MINUTES
	MOVE C,B	;GET HOURS IN C
	JRST ARTIMX	;DEPOSIT HOURS, CONVERT TO SIXBIT, AND RETURN

		;DEPOSIT C(C) AS TWO SIX BIT (AS OPPOSED TO SIXBIT) DECIMAL DIGITS
		; VIA T (INTO A) THEN DECREMENT T

RDATM1:	IDIVI C,10.	;SEPARATE DIGITS
	DPB C,[60600,,D]	;DEPOSIT FIRST DIGIT TO GIVE 12 BITS
	DPB D,T			;OUTPUT BYTE
	ADD T,[140000,,]	;DECREMENT BYTE POINTER
	POPJ P,		;THAT'S ALL

		;DO A PUSHJ P,GLPDTM THEN HACK AROUND
		;DO THOSE THINGS TO E COMMENTED IN GLPDTM AS BEING DONE BY RYEAR
		;TRY TO GET YEAR EVEN IF GLPDTM DOESN'T SKIP, BUT IN THAT CASE CLOBBER A TO -1

RYEAR:	PUSHJ P,GLPDTM	;GET THE CRUFT
	 JRST RYEAR2	;DIDN'T SKIP, SEE WHAT CAN BE SALVAGED
RYEAR1:	PUSH P,A	;PROTECT A FROM FUTURE CLOBBERAGE
	IDIVI A,SPD	;GET LOCALIZED # DAYS SINCE BEGINNING OF YEAR
	JUMPL E,[SOJA A,.+1]	;DE-LOCALIZE
	LDB B,[270300,,E]	;DAY OF WEEK OF BEGINNING OF YEAR
	ADD A,B		;ADD IN
	IDIVI A,7	;GET TODAY'S DAY OF WEEK (0 => SUNDAY) IN B
	DPB B,[320300,,E]	;DEPOSIT IN E
	TLO E,40000	;DOCUMENT FACT THAT TIME OF YEAR KNOWN
	JRST POPAJ	;RESTORE A AND RETURN

RYEAR2:	PUSHJ P,GDWOBY	;GLPDTM DIDN'T SKIP, TRY TO SALVAGE CRUFT: FIRST DOWOBY
	MOVNI A,1	;DOCUMENT FACT THAT TIME OF YEAR NOT KNOWN
	JUMPE E,CPOPJ	;RETURN IF YEAR NOT KNOWN EITHER
	DPB B,[270300,,E]	;DAY OF WEEK OF BEGINNING OF YEAR
	JRST CMPF29	;SEE IF LEAP YEAR, AND RETURN

	;NOTE: THE SYMS JAN, FEB, MAR, ETC. ARE DEFINED AFTER (AND BY) MNIRP (A MACRO)

		;INCREMENT YEAR

NUPDT:	TLNN E,200000			;SEE IF LEAP YEAR
	 SKIPA A,[<365.*SPD*PDUPS>]	;NORMAL YEAR
	  MOVE A,[<366.*SPD*PDUPS>]	;LEAP YEAR
	ADDM A,PDTIME	;UPDATE PDCLK OFFSET
	IDIVI A,30.	;CONVERT TO HALF-SECONDS
	EXCH A,PDYTIM	;ALSO UPDATE BACKUP SYSTEM
	SUBM A,PDYTIM
	AOS FYEAR	;INCREMENT YEAR

		;INSERT OTHER CRUFT HERE IF DESIRED
		;DROPS THROUGH

		;CODING DROPS THROUGH FROM PREVIOUS PAGE
;GET "LOCALIZED" NUMBER OF SECONDS SINCE BEGINNING OF YEAR IN A
	;IF DIVIDED BY # SECONDS IN A DAY,
	;GIVES REMAINDER OF # SECONDS SINCE MIDNIGHT LOCAL TIME
	;QUOTIENT WHEN FED TO DATE GENERATOR ROUTINE ASSUMING LEAP YEAR GIVES CORRECT DATE
;ALSO GET YEAR AND FLAGS (AS RETURNED BY .RYEAR) IN E
	;1.1-2.9 => YEAR (E.G. 1969.)
	;3.1-3.5 ZERO
	;3.6-3.8 => DAY OF WEEK OF BEGINNING OF YEAR (0 => SUNDAY)
	;3.9-4.2 ZERO (RYEAR SETS THIS BYTE TO TODAY'S DAY OF WEEK IF TIME OF YEAR KNOWN)
	;4.6 ZERO (RYEAR SETS IT TO 1 IF TIME OF YEAR KNOWN)
	;4.7 ONE => DAYLIGHT SAVINGS TIME IN EFFECT
	;4.8 ONE => LEAP YEAR
	;4.9 ONE => 365 DAY YEAR AND AFTER FEB 28
;SKIPS IF PDCLK ON AND BOTH PDTIME AND FYEAR NON-ZERO (IN OTHER WORDS IF SUCCESSFUL)
;PREVIOUS CODING DROPS THROUGH ON YEAR INCREMENT

GLPDTM:	CONO PI,CLKOFF	;AVOID DOUBLE YEAR INCREMENT
	SKIPE E,FYEAR	;GET YEAR IN E, SKIP IF NOT AVAILABLE
	 PUSHJ P,GPDTIM	;GET PDTIME, SHOULD SKIP
	  JRST CLKONJ	;SOMETHING NOT AVAILABLE, DON'T SKIP
	IDIVI A,60.	;CONVERT TO SECONDS
	PUSHJ P,CMPF29	;MAYBE SET BIT 4.8 OR 4.9 OF E, IF 4.9 SET THEN ADD SPD TO A
	CAML A,[366.*SPD]	;IF MORE THAN A YEAR HAS GONE,
	 JRST NUPDT	;THEN INCREMENT YEAR
	CONO PI,CLKON	;TIMIMG ERROR PROBLEM GONE
	PUSH P,A	;SAVE # SECONDS DURING NEXT CALL
	PUSHJ P,GDWOBY	;GET DAY OF WEEK OF BEGINNING OF YEAR (0 => SUNDAY)
	DPB B,[270300,,E]	;DEPOSIT IN RIGHT PLACE
	POP P,A		;RESTORE A
	AOS (P)		;CAUSE RETURN TO SKIP

		;IF DAYLIGHT SAVINGS TIME THEN ADD 3600. TO A AND SET BIT 4.7 IN E

GLPDT2:	JFCL		;POPJ FOR STD TIME
			;JRST CRDDST FOR DAY LIGHT TIME
			;JFCL "NORMAL"
	CAML A,[<APR 1>*SPD+7200.]	;IF BEFORE 2AM APR 1,
	CAML A,[<OCT 31.>*SPD+3600.]	;OR IF AFTER 1AM STANDARD TIME OCT 31,
	 POPJ P,			;THEN OBVIOUSLY STANDARD TIME IS IN EFFECT
	CAML A,[<APR 7>*SPD+7200.]	;IF BEFORE 2AM APR 7 STANDARD TIME,
	CAML A,[<OCT 25.>*SPD+3600.]	;OR IF AFTER 1AM STANDARD TIME OCTOBER 25,
	 JRST GLPDT3			;THEN NOT OBVIOUS
CRDDST:	TLO E,100000	;DAYLIGHT SAVINGS TIME, SET BIT IN E
	ADDI A,3600.	;CONTINUE TO LOCALIZE THE TIME THAT WILL BE RETURNED
	POPJ P,

		;IT IS NOW SOMETIME DURING THE WEEKS IN APR AND OCTOBER
		;WHEN IT MAY BE EITHER STANDARD OR DAYLIGHT SAVINGS TIME

GLPDT3:	PUSH P,A	;SAVE # SECS
	CAMG A,[JUL*SPD]	;IF NOT YET JULY,
	 TDZA D,D	;THEN IT MUST BE APR, SET INDEX
	  MOVEI D,1	;OCTOBER, SET INDEX
	SUB A,CRDSB(D)	;COMPENSATE FOR 2AM OR 1AM
	IDIVI A,SPD	;FLUSH SECONDS, LEAVE ONLY DAYS (IT LOOKS LIKE A LEAP YEAR, REMEMBER)
	LDB C,[270300,,E]	;GET DAY OF WEEK OF BEGINNING OF YEAR IN C
	JUMPGE E,.+3	;IF REGULAR YEAR,
	 SOJGE C,.+2	;THEN DE-LOCALIZE SO IT WILL RE-LOCALIZE LATER...
	 MOVEI C,6	;MOD 7
	ADD A,C		;ADD TO NUMBER OF DAYS
	IDIVI A,7
	IMULI A,7
	SUB A,C		;C(A) := NUMBER OF DAYS IN YEAR BEFORE LAST SUNDAY (MAYBE TODAY)
		;IF LAST SUNDAY (AS DEFINED ABOVE) IS BELOW THE "REGION OF AMBIGUITY",
		;THEN IT HAS NOT YET CHANGED TO THE LATER TIME
	XCT CRDTST(D)	;SKIP IF DAYLIGHT SAVINGS TIME
	 JRST POPAJ	;STANDARD TIME, NO CHANGES NECESSARY
	POP P,A		;DAYLIGHT SAVINGS TIME, RESTORE A
	JRST CRDDST	;MUNG A AND E AND RETURN

CRDSB:	7200.		;IN APR CHANGES AT 2AM EST
	3600.		;IN OCTOBER CHANGES AT 1AM EST

CRDTST:	CAIGE A,<APR 1>
	CAIL A,<OCT 25.>

		;IF LEAP YEAR THEN SET BIT 4.8 OF E
		;IF NOT LEAP YEAR THEN IF AFTER FEB 28 THEN SET BIT 4.9 OF E AND ADD SPD TO A

CMPF29:	TRNN E,3	;IF LEAP YEAR, (HOPEFULLY THIS ONLY PLACE WHERE DIRECTLY CHECKED FOR LEAP YEAR)
	 TLOA E,200000	;THEN SET BIT 4.8 OF E AND RETURN
	  CAMGE A,[<<MAR 1>-1>*SPD]	;365 DAY YEAR, IF BEFORE MARCH FIRST,
	   POPJ P,	;THEN RETURN
	TLO E,400000	;365 DAY YEAR AFTER FEB 28, SET BIT 4.9 OF E
	ADDI A,SPD	;INCREMENT A ONE DAY
	POPJ P,

		;GET DAY OF WEEK OF BEGINNING OF YEAR (IN E) (0 => SUNDAY) IN B
		;FOLLOWING ROUTINE HAS BEEN EXHAUSTIVELY CHECKED

GDWOBY:	MOVEI A,-1(E)
	IDIVI A,400.
	MOVEI A,1(B)
	IDIVI B,4
	ADD A,B
	IDIVI B,25.
	SUB A,B
	IDIVI A,7
	POPJ P,

		;SLOW CLOCK ROUTINE TO CHECK ON REAL-TIME CLOCK SYSTEM

PDCCHK:	SKIPL PDYTIM	;IF BACKUP TIME (SINCE BEGINNING OF YEAR) CALCULATED,
	 AOS PDYTIM	;THEN UPDATE IT
	SKIPGE TIMOFF	;IF TIMOFF NOT CALCULATED,
	 POPJ P,	;THEN RETURN
	AOS A,TIMOFF	;UPDATE TIMOFF
	CAMGE A,[2*SPD]	;Incremented beyond length of day?
	 JRST PDCCH1
	SETZB A,TIMOFF	;Yes - reset it.
	MOVEM A,RSWTIM	;Also reset last-resource-warning timestamp.
PDCCH1:	TRNE A,64.*2-1	;Is this a 64. second (based on TIMOFF) clock break?
	 POPJ P,	;  No, so return.
INITIM:
IFN PDCLKP,[
	SKIPN A,PDTIME	;MAYBE UPDATE BACKUP SYSTEM
	 JRST INITM2	;PDTIME NOT AVAILABLE, DON'T
	DATAI PDCLK,B
	TLZ B,600000
	JUMPE B,INITM2	;JUMP IF CLOCK OFF
	SUBM B,A
	JUMPL A,CPOPJ
	IDIVI A,30.	;CONVERT TO HALF-SECONDS SINCE BEGINNING OF YEAR
	MOVEM A,PDYTIM	;STORE RE-CALCULATED BACKUP TIME
] ;PDCLKP
IFN KS10P,[
	SKIPN PDTIME	; Update backup system?
	 JRST INITM2	; Not without offset
	RDTIM A
	TLC A,1729.
	TLNE A,-1
	 JRST INITM2	; Not if clock reset
	DIVI A,KSFREQ
	SUB A,PDTIME	; 60ths since Jan 1
	JUMPL A,CPOPJ
	IDIVI A,30.	; halfs since Jan 1
	MOVEM A,PDYTIM	; Store backup
] ;KS10P
INITM2:	PUSHJ P,GLPDTM	;GET LOCALIZED PDTIME
	 POPJ P,	;SOMETHING'S MISSING
	IDIVI A,SPD	;SEPARATE INTO DAYS AND SECONDS
	LSH B,1		;CONVERT TIME SINCE MIDNIGHT TO HALF-SECONDS
	MOVEM B,TIMOFF	;STORE RE-CALCULATED NUMBER OF HALF-SECONDS SINCE MIDNIGHT
	PUSHJ P,CLCQDT	;GET QDATE,,TIMOFF IN A
	CONO PI,UTCOFF	;INHIBIT INTERRUPTS DURING THIS RITUAL
	SKIPGE A,QMDRO	;GET ORIGIN OF MASTER DSK DIRECTORY
	 JRST UTCONJ	;DIRECTORY LOCKED
	MOVE B,QACTB	;DIRECTORY CHANGED BIT FOR DSK DIRECTORY
	SKIPE T,PDTIME	;GET OFFSET FOR DECORIOLIS CLOCK
	 CAMN T,MPDOFF(A)	;SEE IF IT MATCHES RELEVANT WORD IN DSKDIR
	  JRST .+3		;MATCHES OR PDTIME NOT AVAILABLE
	    MOVEM T,MPDOFF(A)	;NO MATCH, CORRECT THE DSKDIR ONE
	    IORM B,QMDRO	;SET DIRECTORY CHANGED BIT
	SKIPE T,FYEAR	;NOW DO THE SAME FOR THE YEAR,
	 CAMN T,MDYEAR(A)	;AND THE RELEVANT WORD IN DSKDIR
	  JRST .+3
	    MOVEM T,MDYEAR(A)
	    IORM B,QMDRO
	JRST UTCONJ	;THAT'S ALL

CLCQDT:	PUSHJ P,RDATE1	;GET DAY OF MONTH IN C, MONTH IN B
	SETZM QDATE	;INITIALIZE FOR FOLLOWING
	PUSH P,E-1
	PUSH P,E
	MOVE E-1,FYEAR
	IDIVI E-1,100.
	DPB E,[330700,,QDATE]	;YEAR
	POP P,E
	POP P,E-1
	DPB B,[270400,,QDATE]	;MONTH
	DPB C,[220500,,QDATE]	;DAY
	MOVE C,QDATE		;THE FIRST TIME QDATE IS SET UP,
	HRR C,TIMOFF		;SET UP QDATEI = TIME SYSTEM CAME UP.
	SKIPGE QDATEI
	 MOVEM C,QDATEI		;MECHANISM IS, SET QDATEI UNLESS ALREADY SET.
	POPJ P,
